using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TxTReader.Core
{
    /// <summary>
    /// 文件编码检测器
    /// </summary>
    public static class EncodingDetector
    {
        static EncodingDetector()
        {
            // 注册编码提供程序以支持更多编码
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }

        /// <summary>
        /// 安全获取编码，如果失败则返回UTF-8
        /// </summary>
        /// <param name="name">编码名称</param>
        /// <returns>编码对象</returns>
        private static Encoding GetEncodingSafe(string name)
        {
            try
            {
                return Encoding.GetEncoding(name);
            }
            catch
            {
                return Encoding.UTF8;
            }
        }

        /// <summary>
        /// 常见编码列表
        /// </summary>
        public static readonly Encoding[] CommonEncodings = new[]
        {
            Encoding.UTF8,
            GetEncodingSafe("GB2312"),
            GetEncodingSafe("GBK"),
            GetEncodingSafe("Big5"),
            GetEncodingSafe("Shift-JIS"),
            GetEncodingSafe("EUC-KR"),
            Encoding.ASCII,
            Encoding.Unicode,
            Encoding.BigEndianUnicode,
            GetEncodingSafe("ISO-8859-1")
        };

        /// <summary>
        /// 自动检测文件编码
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>检测到的编码</returns>
        public static Encoding DetectFileEncoding(string filePath)
        {
            try
            {
                System.Diagnostics.Debug.WriteLine($"EncodingDetector.DetectFileEncoding: 开始检测文件编码 {filePath}");
                
                // 方法1：使用StreamReader自动检测
                using var reader = new StreamReader(filePath, true);
                var detectedEncoding = reader.CurrentEncoding;
                
                System.Diagnostics.Debug.WriteLine($"EncodingDetector.DetectFileEncoding: StreamReader检测到编码 = {detectedEncoding.EncodingName}");
                
                // 如果检测到的是UTF-8，进一步验证
                if (detectedEncoding == Encoding.UTF8)
                {
                    System.Diagnostics.Debug.WriteLine($"EncodingDetector.DetectFileEncoding: 开始验证UTF-8编码");
                    var verifiedEncoding = VerifyUtf8Encoding(filePath);
                    System.Diagnostics.Debug.WriteLine($"EncodingDetector.DetectFileEncoding: UTF-8验证完成 = {verifiedEncoding.EncodingName}");
                    return verifiedEncoding;
                }
                
                return detectedEncoding;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"EncodingDetector.DetectFileEncoding: StreamReader检测失败 - {ex.GetType().Name}: {ex.Message}");
                // 如果自动检测失败，尝试BOM检测
                return DetectEncodingFromBOM(filePath);
            }
        }

        /// <summary>
        /// 从BOM检测编码
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>检测到的编码</returns>
        private static Encoding DetectEncodingFromBOM(string filePath)
        {
            try
            {
                using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                var bom = new byte[4];
                var bytesRead = fileStream.Read(bom, 0, 4);
                
                if (bytesRead >= 4)
                {
                    // UTF-32 LE
                    if (bom[0] == 0xFF && bom[1] == 0xFE && bom[2] == 0x00 && bom[3] == 0x00)
                        return Encoding.GetEncoding("UTF-32LE");
                    
                    // UTF-32 BE
                    if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == 0xFE && bom[3] == 0xFF)
                        return Encoding.GetEncoding("UTF-32BE");
                }
                
                if (bytesRead >= 3)
                {
                    // UTF-8
                    if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF)
                        return Encoding.UTF8;
                }
                
                if (bytesRead >= 2)
                {
                    // UTF-16 LE
                    if (bom[0] == 0xFF && bom[1] == 0xFE)
                        return Encoding.Unicode;
                    
                    // UTF-16 BE
                    if (bom[0] == 0xFE && bom[1] == 0xFF)
                        return Encoding.BigEndianUnicode;
                }
            }
            catch
            {
                // 忽略错误，返回默认编码
            }
            
            // 默认返回UTF-8
            return Encoding.UTF8;
        }

        /// <summary>
        /// 验证UTF-8编码
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>验证后的编码</returns>
        private static Encoding VerifyUtf8Encoding(string filePath)
        {
            try
            {
                // 读取文件的前几KB来验证UTF-8
                using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                var buffer = new byte[4096];
                var bytesRead = fileStream.Read(buffer, 0, buffer.Length);
                
                // 检查是否包含无效的UTF-8序列
                var text = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                var encoded = Encoding.UTF8.GetBytes(text);
                
                // 如果重新编码后长度不同，可能不是UTF-8
                if (encoded.Length != bytesRead)
                {
                    // 尝试其他编码
                    foreach (var encoding in CommonEncodings)
                    {
                        if (encoding == Encoding.UTF8) continue;
                        
                        try
                        {
                            var testText = encoding.GetString(buffer, 0, bytesRead);
                            var testEncoded = encoding.GetBytes(testText);
                            if (testEncoded.Length == bytesRead)
                            {
                                return encoding;
                            }
                        }
                        catch
                        {
                            continue;
                        }
                    }
                }
                
                return Encoding.UTF8;
            }
            catch
            {
                return Encoding.UTF8;
            }
        }

        /// <summary>
        /// 获取编码的友好名称
        /// </summary>
        /// <param name="encoding">编码</param>
        /// <returns>友好名称</returns>
        public static string GetEncodingDisplayName(Encoding encoding)
        {
            return encoding switch
            {
                var enc when enc == Encoding.UTF8 => "UTF-8",
                var enc when enc == Encoding.Unicode => "UTF-16 LE",
                var enc when enc == Encoding.BigEndianUnicode => "UTF-16 BE",
                var enc when enc == Encoding.ASCII => "ASCII",
                var enc when enc.WebName == "gb2312" => "GB2312",
                var enc when enc.WebName == "gbk" => "GBK",
                var enc when enc.WebName == "big5" => "Big5",
                var enc when enc.WebName == "shift_jis" => "Shift-JIS",
                var enc when enc.WebName == "euc-kr" => "EUC-KR",
                var enc when enc.WebName == "iso-8859-1" => "ISO-8859-1",
                _ => encoding.WebName.ToUpper()
            };
        }

        /// <summary>
        /// 根据名称获取编码
        /// </summary>
        /// <param name="name">编码名称</param>
        /// <returns>编码对象</returns>
        public static Encoding GetEncodingByName(string name)
        {
            return name switch
            {
                "UTF-8" => Encoding.UTF8,
                "UTF-16 LE" => Encoding.Unicode,
                "UTF-16 BE" => Encoding.BigEndianUnicode,
                "ASCII" => Encoding.ASCII,
                "GB2312" => GetEncodingSafe("GB2312"),
                "GBK" => GetEncodingSafe("GBK"),
                "Big5" => GetEncodingSafe("Big5"),
                "GB2312 (简体中文)" => GetEncodingSafe("GB2312"),
                "GBK (中文扩展)" => GetEncodingSafe("GBK"),
                "Big5 (繁体中文)" => GetEncodingSafe("Big5"),
                "Shift-JIS (日文)" => GetEncodingSafe("Shift-JIS"),
                "EUC-KR (韩文)" => GetEncodingSafe("EUC-KR"),
                "ISO-8859-1 (西欧)" => GetEncodingSafe("ISO-8859-1"),
                _ => GetEncodingSafe(name)
            };
        }
    }
}
